package cn.foolishbird.crow.encrypt.springmvc;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.ServletServerHttpRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author foolish-bird
 */
public class CacheServletServerHttpRequest extends ServletServerHttpRequest {

    /**
     * 日志
     */
    private static final Logger log = LoggerFactory.getLogger(CacheServletServerHttpRequest.class);

    /**
     * body数组
     */
    private byte[] bodyByte;

    /**
     * 缓冲body
     */
    private ByteArrayInputStream bodyInputStream;


    public CacheServletServerHttpRequest(HttpServletRequest request) {
        super(request);
        try {
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            IOUtils.copy(request.getInputStream(), buffer);
            this.bodyByte = buffer.toByteArray();
            this.bodyInputStream = new ByteArrayInputStream(bodyByte);
        } catch (IOException e) {
            log.error("获取inputStream失败：{}", e);
            throw new RuntimeException("获取inputStream失败");
        }
    }


    @Override
    public InputStream getBody() throws IOException {
        if (isFormPost(this.getServletRequest())) {
            return getBodyFromServletRequestParameters(this.getServletRequest());
        } else {
            return this.bodyInputStream;
        }
    }

    private static boolean isFormPost(HttpServletRequest request) {
        String contentType = request.getContentType();
        return (contentType != null && contentType.contains(FORM_CONTENT_TYPE) &&
                HttpMethod.POST.matches(request.getMethod()));
    }

    private static InputStream getBodyFromServletRequestParameters(HttpServletRequest request) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
        Writer writer = new OutputStreamWriter(bos, FORM_CHARSET);

        Map<String, String[]> form = request.getParameterMap();
        for (Iterator<String> nameIterator = form.keySet().iterator(); nameIterator.hasNext(); ) {
            String name = nameIterator.next();
            List<String> values = Arrays.asList(form.get(name));
            for (Iterator<String> valueIterator = values.iterator(); valueIterator.hasNext(); ) {
                String value = valueIterator.next();
                writer.write(URLEncoder.encode(name, FORM_CHARSET.name()));
                if (value != null) {
                    writer.write('=');
                    writer.write(URLEncoder.encode(value, FORM_CHARSET.name()));
                    if (valueIterator.hasNext()) {
                        writer.write('&');
                    }
                }
            }
            if (nameIterator.hasNext()) {
                writer.append('&');
            }
        }
        writer.flush();

        return new ByteArrayInputStream(bos.toByteArray());
    }

    public byte[] getBodyByte() {
        return bodyByte;
    }

    public void setBodyByte(byte[] bodyByte) {
        this.bodyByte = bodyByte;
    }
}
